package fxification.test;

import fxification.io.IO;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import junit.framework.Assert;
import java.lang.Throwable;
import java.io.BufferedReader;
import fxification.java.FxIO;
import java.io.File;

public class IOTest extends TestCase{

    public function testFileReadLines():Void {
        var count = 0;
        def f = IO.File{
            name:"{__DIR__}TestFile.txt"
            onReadLine:function(l:String){
                count++;
            }
            onDone:function(count:Long){
                Assert.assertEquals(204, count);
            }
        };
        f.readLines();
        Assert.assertEquals(204, count);
    }

    public function testFileReadLinesOutsideJar() {
        var count = 0;
        var failCount = 0;
        def f = IO.File{
            name:"dir-for-test/TestFile.txt"
            onReadLine:function(l:String){
                count++;
            }
            onDone:function(count:Long){
                Assert.assertEquals(204, count);
            }
            onFailure:function(ex:Throwable){
                failCount;
            }
        };
        f.readLines();
        Assert.assertEquals(204, count);
        Assert.assertEquals(0, failCount);
    }

    public function testFileReadLinesException() {
        try{
        var count = 0;
        def f = IO.File{
            name:"{__DIR__}TestFile"
            onReadLine:function(l:String){
                count = 1;
            }
            onDone:function(c:Long){
                count = 1;
            }
            onFailure:function(ex:Throwable){
                count = 0;
            }
        };
        f.readLines();
        Assert.fail("Test should have failed due to bad file name.");
        }catch(ex){}// should fail}
    }

    public function testFunctionalFileReadLines() {
        var count = 0;
        IO.File{name:"{__DIR__}TestFile.txt"}.doWithEachLine(
            function(l:String){
                count++;
                return;
            }
        );
        Assert.assertEquals(204, count);
    }

    public function testFileReadBytes () {
        var count:Long;
        def f = IO.File{
            name:"{__DIR__}TestFile.txt"
            onReadBytes:function(buff:nativearray of Byte, bytesRead:Integer){
                count = count + bytesRead
            }
            onDone:function(length:Long){
                count = length;
            }
        };
        f.readBytes();
        Assert.assertEquals(2181, count);
    }

    public function testFunctionalFileReadBytes() {
        var count:Integer = 0;
        IO.File{name:"{__DIR__}TestFile.txt"}.doWithBytes(
            function(bytes:nativearray of Byte, bytesRead:Integer){
                count = count + bytesRead;
                return;
            }
        );
        Assert.assertEquals(2181, count);
    }

    public function testTraverseDir ():Void {
        var count = 0;
        def f = IO.File {
            name:"./dir-for-test"
            onEachFile:function(file:java.io.File){
                count++;
            }
        }
        f.traverseDir();

        Assert.assertEquals (4, count)
    }

    public function testFunctionalDirTraversal() {
        var count:Integer = 0;
        IO.File{name:"./dir-for-test"}.doWithEachFile(
            function(file:java.io.File){
                count++;
                return;
            }
        );
        Assert.assertEquals(4, count);
    }

    public function testDoWithInputStream():Void {
        IO.File{name:"./dir-for-test/TestFile.txt"}.doWithInputStream(
            function(stream:java.io.InputStream){
                Assert.assertNotNull(stream);
                Assert.assertEquals(2181, stream.available());
            }
        );
    }

    public function testDoWithInputStreamReader(): Void {
        IO.File{name:"./dir-for-test/TestFile.txt"}.doWithInputStreamReader(
            function(stream:java.io.InputStreamReader){
                Assert.assertNotNull(stream);
                var reader = new BufferedReader(stream);
                var counter = 0;
                while(reader.readLine() != null){
                    counter++
                }
                Assert.assertEquals(204,counter);
            }
        );
    }

    public function testGetInputStream():Void {
        Assert.assertNotNull(IO.File{name:"./dir-for-test/TestFile.txt"}.getInputStream());
    }

    public function testGetInputStreamReader():Void {
        Assert.assertNotNull(IO.File{name:"./dir-for-test/TestFile.txt"}.getReader());
    }

    public function testWriteLines() {
        def fileName = "./dir-for-test/a.text";
        var file = IO.File{name:fileName};
        var counter = 0;
        file.onWriteLine = function(l:String){
            counter++;
        }
        file.writeLines([
            "Line 1\n",
            "Line 2\n",
            "Line 3\n",
            "Line 4\n",
            "Line 5\n"
        ]);

        Assert.assertEquals(counter, 5);

        while(new java.io.File(fileName).delete() != true){
            java.lang.Thread.currentThread().sleep(100);
        }
    }

    public function testWriteBytes() {
        def fileName = "./dir-for-test/b.text";
        var file = IO.File{name:fileName};
        var counter = 0;
        var bytes = new String(
            "Line 1\n"
            "Line 2\n"
            "Line 3\n"
            "Line 4\n"
            "Line 5"
        ).getBytes();

        file.onWriteByte = function(b:nativearray of Byte){
            counter = b.length;
        }
        
        file.writeBytes(bytes);

        Assert.assertEquals(34, counter);

        while(new java.io.File(fileName).delete() != true){
            java.lang.Thread.currentThread().sleep(100);
        }
    }

    public function testDoWithOutputStream(){
        def fileName = "./dir-for-test/b.text";
        IO.File{name:fileName}.doWithOutputStream(
            function(stream:java.io.OutputStream){
                stream.write(
                    new String(
                        "Line 1\n"
                        "Line 2\n"
                        "Line 3\n"
                        "Line 4\n"
                        "Line 5"
                    ).getBytes()
                );
                FxIO.closeOutputStream(stream);
            }
        );

        var file = new java.io.File(fileName);
        Assert.assertTrue(file.exists());
        Assert.assertEquals(34, file.length());

        while(file.delete() != true){
            java.lang.Thread.currentThread().sleep(100);
        }
    }


    public function testDoWithOutputStreamWriter(){
        def fileName = "./dir-for-test/b.text";
        IO.File{name:fileName}.doWithOutputStreamWriter(
            function(stream:java.io.OutputStreamWriter){
                stream.write(
                    new String(
                        "Line 1\n"
                        "Line 2\n"
                        "Line 3\n"
                        "Line 4\n"
                        "Line 5"
                    )
                );
                FxIO.closeWriter(stream);
            }
        );

        var file = new java.io.File(fileName);
        Assert.assertTrue(file.exists());
        Assert.assertEquals(34, file.length());

        while(file.delete() != true){
            java.lang.Thread.currentThread().sleep(100);
        }
    }

    public function testDoWithPrintWriter(){
        def fileName = "./dir-for-test/b.text";
        IO.File{name:fileName}.doWithPrintWriter(
            function(stream:java.io.PrintWriter){
                stream.write(
                    new String(
                        "Line 1\n"
                        "Line 2\n"
                        "Line 3\n"
                        "Line 4\n"
                        "Line 5"
                    )
                );

                FxIO.closeWriter(stream);
            }
        );

        var file = new java.io.File(fileName);
        Assert.assertTrue(file.exists());
        Assert.assertEquals(34, file.length());

        while(file.delete() != true){
            java.lang.Thread.currentThread().sleep(100);
        }
    }

//    public function testAsyncFileRead() {
//        var count = 0;
//        TaskRunner.runTask(
//            function(){
//                IO.File{name:"{__DIR__}TestFile.txt"}.doWithEachLine(
//                    function(l:String){
//                        count++;
//                        return;
//                    }
//                );
//            },
//            function(){
//                Assert.assertEquals(204, count);
//            }
//        );
//    }

}

public function run() {
    def test = TestRunner{};
    test.run(test.getTest(IOTest.class.getName()));
}
